布朗运动

布朗运动是指悬浮在液体或气体中的微粒所做的永不停息的无规则运动。其因由英国植物学家布朗所发现而得名。作布朗运动的微粒的直径一般为$10^{-5}~10^{-3}$厘米,这些小的微粒处于液体或气体中时,由于液体分子的热运动,微粒受到来自各个方向液体分子的碰撞,当受到不平衡的冲撞时而运动,由于这种不平衡的冲撞,微粒的运动不断地改变方向而使微粒出现不规则的运动。布朗运动的剧烈程度随着流体的温度升高而增加。

蒙特卡洛模拟

蒙特卡洛方法(或蒙特卡洛实验)是一大类计算算法,它们依赖于重复随机采样来获得数值结果。基本思想是使用随机性来解决原则上可能是确定性的问题。它们通常用于物理和数学问题,并且在难以或不可能使用其他方法时最有用。Monte Carlo 方法主要用于三个不同的问题类别:优化、数值积分和从概率分布中生成绘图。

蒙特卡洛模拟预测股价

我们将使用蒙特卡洛模拟来观察资产价格随时间的潜在变化,假设它们的每日收益服从正态分布。这种类型的价格演变也称为“随机游走”(random walk),与布朗运动类似。

股票价格的随机游走指股票的价格变化是随机的,没有固定不变的规律可循的现象。股票的随机游走理论认为,股票价格的波动就像一个醉汉在广场上行走一样,价格的下一步将走向哪里,是没有规律的。在股票市场中,价格的走向受到多方面因素的影响。一件不起眼的小事也可能对市场产生巨大的影响。从长时间的价格走势图上也可以看出,价格的上下起伏的机会差不多是均等的。

随机游走理论指出,股票市场内有成千上万的精明人士,每一个人都懂得分析,而且信息流入市场都是公开的,所有人都可以知道,并无什么秘密可言。因此,股票现在的价格就已经反映了供求关系,或者不会偏离其内在价值太远。所谓内在价值的衡量方法就是由每支股票的资产值、市盈率、派息率等基本因素所决定。这些因素亦非什么大秘密。现时股票的市价根本已经代表了千万精明人士的看法,构成了一个合理价位。市价会围绕着内在价值而上下波动。这些波动却是随意而没有任何轨迹可循的。

假设股票价格符合几何布朗运动, 即 $$ d S_t=\mu_t S_t d t+\sigma_t S_t d W_t $$ 简化处理, 得到特定时期 $(0, T)$ 资产价格变化过程 : $$ \Delta S_t=S_t\left(\mu \Delta t+\sigma \varepsilon_t \sqrt{\Delta t}\right), t=1,2, \ldots, N, N \Delta t=T $$ 于是得到 : $$ S_{t+1}=S_t+S_t\left(\mu \Delta t+\sigma \varepsilon_t \sqrt{\Delta t}\right), t=1,2, \ldots, N, N \Delta t=T $$ 也可表示为: $$ S_{t+1}=S_t e^{\left(\mu-\frac{\sigma^2}{2}\right) \Delta t+\sigma \varepsilon_t \sqrt{\Delta t}} $$ 其中 $\mu$ 为收益率均值, $\sigma^2$ 为收益率方差, $\varepsilon$ 服从 $\mathrm{t}$ 分布或正态分布。 则收益率为: $$ \text { return }=\left(\mu-\frac{\sigma^2}{2}\right) d t+\sigma \varepsilon_t \sqrt{d t} $$

代码

收益率模拟

生成收益率

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import pandas as pd
import math
'''
s:股票现价
t:期限(年)
r:股票年化收益率
sigma:股票年化波动率
nper_per_year:每年的期数
'''
def generate_simulated_stock_returns(t,r,sigma,nper_per_year):      
    simulated_returns=[] # 模拟收益列表
    dt=1/nper_per_year # 时间步长
    term = int(t*nper_per_year) # 总步数
    for i in range (1, term+1): # 循环
        z=np.random.normal() # 生成随机数
        simulated_return = (r-(sigma**2/2))*dt + z*sigma*(dt**(1/2)) # 每一步的收益率
        simulated_returns.append(simulated_return)
    array_return=np.array(simulated_returns)
    return array_return # 返回收益率列表

收益率模拟

# 初始股价s:100; 预期收益率r:10%;标准差:30%
s=100;r=0.1;sigma=0.3
#1年期、每年2期
t=1;nper_per_year=2
array_return = generate_simulated_stock_returns(t,r,sigma,nper_per_year) # 给定时间段内模拟的收益情况
print(array_return)
#2年期、每年24期
t=2;nper_per_year=24
array_return = generate_simulated_stock_returns(t,r,sigma,nper_per_year)
print(array_return)

模拟结果:

[ 0.2036485  -0.03690405]
[-5.67879573e-02 -1.50695772e-01 -2.02143246e-02 -8.95025542e-02
  1.37811181e-02 -6.09740556e-03 -1.07994482e-01 -1.68587127e-02
 -3.00131945e-02  8.16927970e-02  4.82029724e-02  9.11538915e-05
 -1.67817870e-02  9.68631356e-02  8.83046236e-03 -6.31036222e-03
  1.53658495e-01 -3.86113429e-03 -3.03457205e-02 -1.32265098e-02
  2.08610298e-02 -8.70543640e-02 -1.21983018e-01 -3.11792750e-02
  9.34654325e-02  1.92087279e-02  2.63060543e-02 -2.27438684e-03
 -6.44248685e-02  7.74814088e-02  1.75881201e-02  1.55192211e-02
  2.56315211e-02  4.88165057e-02  1.25857837e-01 -6.49697815e-02
 -1.01008302e-02  5.88930096e-02 -2.86574003e-02  2.28076867e-02
  1.71816157e-01 -4.24743663e-02 -1.72081274e-02  6.90818724e-02
  1.39372010e-02  2.08794391e-02  7.60186420e-02 -1.07722670e-01]

股价模拟

生成股价

def generate_simulated_stock_values(s,t,r,sigma,nper_per_year):
    rate=generate_simulated_stock_returns(t,r,sigma,nper_per_year)
    stock_price = [s]
    term = int(t*nper_per_year)
    for i in range(1, term+1):
        values = stock_price[i-1]*math.e**(rate[i-1])
        stock_price.append(values)
    array_price = np.array(stock_price)
    return array_price

股价模拟

#1年期、每年2期
t=1;nper_per_year=2
array_price = generate_simulated_stock_values(s,t,r,sigma,nper_per_year)
print(array_price)
#2年期、每年24期
t=2;nper_per_year=24
array_price = generate_simulated_stock_values(s,t,r,sigma,nper_per_year)
print(array_price)

绘制股价

绘制股价函数

def plot_simulated_stock_values(s,t,r,sigma,nper_per_year,num_trials=1):
    term = int(t*nper_per_year) + 1
    x_axis = np.linspace(0,t,term)
    for i in range(num_trials):
        price=generate_simulated_stock_values(s,t,r,sigma,nper_per_year)
        plt.plot(x_axis, price)
    plt.title(str(num_trials)+" simulated trials")
    plt.xlabel("years")
    plt.ylabel("value")
    plt.show()

模拟5次

# 2年期、每年250期,模拟5次
t=2;nper_per_year=250;num_trials=5
plot_simulated_stock_values(s,t,r,sigma,nper_per_year,num_trials)

模拟1000次

# 2年期、每年250期,模拟1000次
t=2;nper_per_year=250;num_trials=10000
plot_simulated_stock_values(s,t,r,sigma,nper_per_year,num_trials)

参考资料: